package com.tueye.base.util;

import java.io.Serializable;
import java.sql.SQLException;
import java.util.Collection;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.transform.ResultTransformer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Scope;
import org.springframework.dao.DataAccessException;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;

 

/**
 * 
 * @author hanxiaowei
 * 
 */

@Scope("prototype")
@Component("baseHbnDao")
public class BaseHbnDaoImpl extends HibernateDaoSupport implements IBaseHbnDao {

	private final Log log = LogFactory.getLog(BaseHbnDaoImpl.class);

	@Autowired
	public BaseHbnDaoImpl(@Qualifier("sessionFactory")
	SessionFactory sessionFactory) {

		this.setSessionFactory(sessionFactory);
	}

	public BaseHbnDaoImpl() {
	}

	public Object save(final Object entity) throws DataAccessException {

		return this.getHibernateTemplate().save(entity);
	}

	public void saveOrUpdate(final String entityName, final Object entity)
			throws DataAccessException {
		this.getHibernateTemplate().saveOrUpdate(entityName, entity);
	}

	public void saveOrUpdateAll(final Collection entities)
			throws DataAccessException {
		this.getHibernateTemplate().saveOrUpdateAll(entities);
	}

	public void update(final String entityName, final Object entity)
			throws DataAccessException {
		this.getHibernateTemplate().update(entityName, entity);
	}

	public void saveOrUpdate(final Object entity) throws DataAccessException {

		this.getHibernateTemplate().saveOrUpdate(entity);
	}

	public void delete(final Object entity) throws DataAccessException {
		this.getHibernateTemplate().delete(entity);
	}

	public void delete(final String hql) throws DataAccessException {
		this.getHibernateTemplate().delete(hql);
	}

	public void deleteAll(final Collection entities) throws DataAccessException {
		this.getHibernateTemplate().deleteAll(entities);
		
	}

	public Object findById(final Class entityClass, final Serializable id)
			throws DataAccessException {

		return this.getHibernateTemplate().get(entityClass, id);
	}

	public Object findByIdFlush(final Class entityClass, final Serializable id)
			throws DataAccessException {

		Object o = this.getHibernateTemplate().get(entityClass, id);
		this.getSession().evict(o);
		return o;
	}

	public List findByNamedQuery(final String queryName, final Object[] values)
			throws DataAccessException {

		return this.getHibernateTemplate().findByNamedQuery(queryName, values);
	}

	public Session getCurrSession() throws DataAccessException {

		if (this.getSession() == null)
			return this.getSession(true);
		else
			return this.getSession();
	}

	public Object loadById(final Class entityClass, final Serializable id) {

		return this.getHibernateTemplate().load(entityClass, id);
	}

	public List queryList(final String hql) throws DataAccessException { 
	//	return this.getHibernateTemplate().find(hql);
//		return	(List) this.getHibernateTemplate().execute(new HibernateCallback(){
//		       public Object doInHibernate(Session session) throws HibernateException, SQLException
//		       {
//		    	    Query query  =  session.createQuery(hql); 
//		    	   return query.list();
//		       }}
//		       );  
		List result  = this.getHibernateTemplate().find(hql);
		return result;
//		return (List) this.getHibernateTemplate().execute(new HibernateCallback(){
//			public Object doInHibernate(Session session) throws HibernateException, SQLException
//			{
//				Query query = session.createQuery(hql);
//				return query.list();
//			}
//		});
		
//		Query q = this.getSession().createQuery(hql);
//		return q.list();
	}

	public void update(Object obj) {
		// TODO Auto-generated method stub
		this.getHibernateTemplate().update(obj);
		
	}

	public void bussFlush(boolean flush) {
		if (flush) {
			this.getSession().flush();
		}
	}

	public Page pagedQueryByHQL(final String hql, final int pageNo,
			final int pageSize, final Object... values) {
		return pagedQueryByHQL(hql, pageNo, pageSize, null, values);
	}

	/**
	 * 分页查询函数，使用hql.
	 * 
	 * @param pageNo
	 *            页号,从1开始.
	 */
	public Page pagedQueryByHQL(final String hql, final int pageNo,
			final int pageSize, final ResultTransformer resultTransformer,
			final Object... values) {

		Assert.hasText(hql);
		Assert.isTrue(pageNo >= 1, "pageNo should start from 1");
		// Count查询
		String countQueryString = " select count (*) "
				+ removeSelect(removeOrders(hql));
		List countlist = getHibernateTemplate().find(countQueryString, values);
		long totalCount = (Long) countlist.get(0);

		if (totalCount < 1)
			return new Page();
		// 实际查询返回分页对象
		final int startIndex = Page.getStartOfPage(pageNo, pageSize);
//		Query query = values == null ? createQuery(hql) : createQuery(hql,
//				values);
		Query query = null;
		if (resultTransformer != null)
			query.setResultTransformer(resultTransformer);

//		List list = query.setFirstResult(startIndex).setMaxResults(pageSize)
//				.list();
		List list = (List) this.getHibernateTemplate().execute(new HibernateCallback(){
		       public Object doInHibernate(Session session) throws HibernateException, SQLException
		       {
		    	    Query query = null;
		    	   if(values == null){
		    		   query =  session.createQuery(hql);
		    	   }else{
		    		   query =  session.createQuery(hql);
		    		   for (int i = 0; i < values.length; i++) {
		    				query.setParameter(i, values[i]);
		    			}
		    	   } 
		    	   List list = query.setFirstResult(startIndex).setMaxResults(pageSize).list(); 
		    	   return list;
		       }}
		       ); 
		return new Page(startIndex, totalCount, pageSize, list);
	}

	/**
	 * 去除hql的select 子句，未考虑union的情况,用于pagedQuery.
	 * 
	 * @see #pagedQuery(String,int,int,Object[])
	 */
	private static String removeSelect(String hql) {
		Assert.hasText(hql);
		int beginPos = hql.toLowerCase().indexOf("from");
		Assert.isTrue(beginPos != -1, " hql : " + hql
				+ " must has a keyword 'from'");
		return hql.substring(beginPos);
	}

	/**
	 * 去除hql的orderby 子句，用于pagedQuery.
	 * 
	 * @see #pagedQuery(String,int,int,Object[])
	 */
	private static String removeOrders(String hql) {
		Assert.hasText(hql);
		Pattern p = Pattern.compile("order\\s*by[\\w|\\W|\\s|\\S]*",
				Pattern.CASE_INSENSITIVE);
		Matcher m = p.matcher(hql);
		StringBuffer sb = new StringBuffer();
		while (m.find()) {
			m.appendReplacement(sb, "");
		}
		m.appendTail(sb);
		return sb.toString();
	}

	/**
	 * 创建Query对象.
	 * 对于需要first,max,fetchsize,cache,cacheRegion等诸多设置的函数,可以在返回Query后自行设置.
	 * 留意可以连续设置,如下：
	 * 
	 * <pre>
	 * dao.getQuery(hql).setMaxResult(100).setCacheable(true).list();
	 * </pre>
	 * 
	 * 调用方式如下：
	 * 
	 * <pre>
	 *        dao.createQuery(hql)
	 *        dao.createQuery(hql,arg0);
	 *        dao.createQuery(hql,arg0,arg1);
	 *        dao.createQuery(hql,new Object[arg0,arg1,arg2])
	 * </pre>
	 * 
	 * @param values
	 *            可变参数.
	 */
	public Query createQuery(String hql, Object... values) {
		Assert.hasText(hql);
		Query query = getSession().createQuery(hql);
		for (int i = 0; i < values.length; i++) {
			query.setParameter(i, values[i]);
		}
		return query;
	}

	 
	public List find(String hql, Serializable id) throws DataAccessException {

		return this.getHibernateTemplate().find(hql, id);
	}

	 
	public List findByHqlQuery(String hql, Object[] values)
			throws DataAccessException {

		return this.getHibernateTemplate().find(hql, values);
	}

	 
	public List queryBySqlList(final String sql) throws DataAccessException { 
		return	(List) this.getHibernateTemplate().execute(new HibernateCallback(){
		       public Object doInHibernate(Session session) throws HibernateException, SQLException
		       {
		    	    Query query  =  session.createSQLQuery(sql); 
		    	   return query.list();
		       }}
		       );  
	}

	 
	public void merge(Object entity) throws DataAccessException {
		// TODO Auto-generated method stub
		this.getHibernateTemplate().merge(entity);
	}
	public void deleteSql(final String sql){
		this.getHibernateTemplate().execute(new HibernateCallback() {

        public Object doInHibernate(Session session) throws HibernateException, SQLException {
            Query q = session.createSQLQuery(sql);
            q.executeUpdate();
            return null;
        }
        
    }); 
		}

	public void updatebatch(final String hql) {
		// TODO Auto-generated method stub

		this.getHibernateTemplate().execute(new HibernateCallback() {

        public Object doInHibernate(Session session) throws HibernateException, SQLException {
            Query q = session.createQuery(hql);
            q.executeUpdate();
            return null;
        }
        
    }); 
		
	}
}
